home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 2006 December
/
PCWorld_2006-12_cd.bin
/
v cisle
/
ophcrack
/
ophcrack-win32-installer-2.3.3.exe
/
{app}
/
src
/
ophcrack.c
< prev
next >
Wrap
C/C++ Source or Header
|
2006-10-11
|
42KB
|
1,576 lines
/*
Ophcrack is a Lanmanager/NTLM hash cracker based on the faster time-memory
trade-off using rainbow tables.
Created with the help of: Maxime Mueller, Luca Wullschleger, Claude
Hochreutiner, Andreas Huber and Etienne Dysli.
Copyright 2006 Philippe Oechslin, Cedric Tissieres
Ophcrack is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Ophcrack is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Ophcrack; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
This program is released under the GPL with the additional exemption
that compiling, linking, and/or using OpenSSL is allowed.
*/
/* LanManager/NTLM password cracker using a Time-Memory Trade-Off */
/*
* $Log: ophcrack.c,v $
* Revision 2.3.3 2006/10/11 tissieres
* save tables directory, error msg when no tables
*
* Revision 2.3.2 2006/10/10 tissieres
* Patched for FreeBSD
*
* Revision 2.3 2006/07/21 tissieres oechslin
* Support for Mac OS X Intel, NTLM tables, linear search, Windows preload, ...
*
* Revision 2.2 2006/03/20 tissieres oechslin dysli
* Support for extended charset, memory management
*
* Revision 2.1 2005/12/06 tissieres
* Added tables modification feature, readahead
*
* Revision 2.0 2005/03/24 tissieres
* Modified for GUI
*
* Revision 1.1 2004/09/13 14:26:02 oechslin
* Fixed bug in -q option
*
* Revision 1.0 2004/07/10 19:06:46 oechslin
* Initial revision
*
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#ifndef WIN32
#include <sys/times.h>
#include <sys/mman.h>
/* On *BSD, MAP_ANON is used instead of MAP_ANONYMOUS */
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON
#endif
#if HAVE_SYS_SYSINFO_H
#include <sys/sysinfo.h>
#elif HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#else /* WIN32 */
#include <sys/time.h>
#include <windows.h>
#endif /* WIN32 */
#include <sys/stat.h>
#include "make_hash.h"
#include "make_redux.h"
#include "ophcrack.h"
#ifdef WIN32
#define bzero(p, l) memset(p, 0, l)
#endif /* WIN32 */
#define RAM_FOR_SYSTEM 150 //amount of ram left for the system
#define NB_CHECKPOINTS 2
/* command line options */
int magic_chains = 0,
stats = 0,
verbose = 0,
batch_mode = 0,
batch_tables = 1,
quiet = 0,
ident_col = 99999,
cols = 0,
offset = 0,
first_table = 0,
last_table = 20,
chkpt1 = -1,
chkpt2 = -1;
int checkpoint_value[2];
int STOP = 0,
open_tables = 0,
last_table_save,
batch_tables_save,
table_type = -1,
chars_size = -1;
unsigned char
lm_hash1[MAX_HASH+1][8]={{0}},
lm_hash2[MAX_HASH+1][8]={{0}},
nt_hash[MAX_HASH+1][16]={{0}},
empty_hash[8]={0xaa,0xd3,0xb4,0x35,0xb5,0x14,0x04,0xee},
empty_nt_hash[16]={0x31,0xd6,0xcf,0xe0,0xd1,0x6a,0xe9,0x31,0xb7,0x3c,0x59,0xd7,0xe0,0xc0,0x89,0xc0};
int to_go, hashes=0, n=0, done1[MAX_HASH+1]={0},done2[MAX_HASH+1]={0}, userid[MAX_HASH+1], done_nt[MAX_HASH+1]={0};
char directory[128], info[MAX_HASH+1][64]={{0}}, password[MAX_HASH+1][16]={{0}},
password1[MAX_HASH+1][8]={{0}}, password2[MAX_HASH+1][8]={{0}};
char crack_type[] = "LM";
int crack_type_num = 0;
#ifndef WIN32
FILE *startfile[20],*endfile[20],*indexfile[20];
#else
HANDLE startfile[20], endfile[20], indexfile[20];
unsigned char *startbuff[20],*endbuff[20],*indexbuff[20] = {0};
#endif
int F_INDEX=0, F_START=0, F_END=0;
unsigned long long int offset_nt[] = {0ULL, 95ULL, 9120ULL, 866495ULL,
82317120ULL, 7820126495ULL, 742912017120ULL,
4264526623328ULL};
extern unsigned char nt_chars_low36[];
extern unsigned char nt_chars_alphanum62[];
extern unsigned char nt_chars_ext95[];
/* statistics */
int n_search = 0,
n_fseek = 0,
n_hashredux = 0,
n_false = 0,
n_false_redux = 0,
n_match = 0,
n_loop = 0,
n_found = 0,
n_cp_false = 0;
struct tms n_times;
int ticks;
clock_t n_start_time, laps_time;
unsigned long int size_to_clean = 0;
#ifdef WIN32
char *
strsep(char** stringp, const char* delim)
{
char *s;
const char *spanp;
int c, sc;
char *tok;
if ((s = *stringp) == NULL)
return (NULL);
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
#endif
/* void usage(char *name)
{
printf("usage %s [-pvsb -d directory -f first -i row -l last -n tables] -t columns lmhash[:nthash]ªhash_file_name\n",name);
printf(" -d directory where tables saved\n");
printf(" -t columns per table\n");
printf(" -o table offset (if not equal to t)\n");
printf(" -i appliy identical redux starting at this column \n");
printf(" -v verbose mode\n");
printf(" -s generate statistics\n");
printf(" -q quiet (no progress indication)\n");
printf(" -f first table (default 0)\n");
printf(" -l last table (default 2^31-1)\n");
printf(" -n number of tables to use at a time\n");
printf("\n\n");
printf(" Hashes can be provided in the following hex formats:\n");
printf(" lmhash\n");
printf(" lmhash:nthash\n");
printf(" username:userid:lmhash:nthash:other fieds (as provided by pwdump)\n");
printf(" or the name of a file containing such hashes, one on each line.\n\n");
exit(-1);
}
*/
/* void print_stats() {
clock_t t;
t = times(&n_times);
printf("\nStatistics: \n hash-redux calculations: %d\n",
n_hashredux);
printf(" endpoint searched %d\n fseek operations %d\n",
n_search, n_fseek);
printf(" matches found %d\n false alarms %d\n",
n_match,
n_false);
printf(" hash-redux operations per false alarms %d\n",
(n_false? n_false_redux/n_false: 0));
printf(" time elapsed %5.2fs\n\n",
(float)(t-n_start_time)/ ticks );
}
*/
void init_stats() {
n_hashredux=0;
n_search=0;
n_fseek=0;
n_false=0;
n_false_redux=0;
n_match=0;
#ifndef WIN32
n_start_time = times(&n_times);
#else /* WIN32 */
n_start_time = clock();
#endif /* WIN32 */
}
/* Open all the files
=================== */
int open_files()
{
unsigned char filename[256];
int table;
first_table=0;
#ifdef WIN32
int error;
#endif
/* for all available tables */
for (table=first_table; table<=last_table; table++) {
/* end points */
sprintf((char *)filename,"%s/table%d.bin",directory,table);
#ifndef WIN32
if (!(endfile[table]=fopen((char *)filename,"r"))) {
#else
endfile[table]= CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN, 0);
if (GetLastError()) {
#endif
last_table = table-1;
break; /* all tables searched */
}
/* starting points */
sprintf((char *)filename,"%s/table%d.start",directory,table);
#ifndef WIN32
if (!(startfile[table]=fopen((char *)filename,"r")))
#else
startfile[table]= CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN, 0);
if (GetLastError())
#endif
g_print ("cannot open table file");
/* index table */
sprintf((char *)filename,"%s/table%d.index",directory,table);
#ifndef WIN32
if (!(indexfile[table]=fopen((char *)filename,"r")))
#else
indexfile[table]= CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN, 0);
if (GetLastError())
#endif
g_print ("cannot open index file");
}
if (table != first_table) {
//if (verbose) printf(" found tables %d through %d\n",first_table, last_table);
open_tables = 1;
last_table_save = last_table;
batch_tables_save = batch_tables;
return 1;
} else {
printf(" found no tables!\n");
return 0;
}
}
int close_files()
{
int table;
#ifdef WIN32
int error;
#endif
batch_tables = batch_tables_save;
last_table = last_table_save;
first_table = 0;
open_tables = 0;
/* for all available tables */
for (table=first_table; table<=last_table; table++) {
#ifndef WIN32
fclose(endfile[table]);
fclose(startfile[table]);
fclose(indexfile[table]);
#else
CloseHandle(endfile[table]);
CloseHandle(startfile[table]);
CloseHandle(indexfile[table]);
if (F_START && startbuff[table]) {
free(startbuff[table]);
startbuff[table] = 0;
}
if (F_END && endbuff[table]){
free(endbuff[table]);
endbuff[table] = 0;
}
if (F_INDEX && indexbuff[table]){
free(indexbuff[table]);
indexbuff[table] = 0;
}
#endif
}
F_INDEX=0; F_START=0; F_END=0;
return 1;
}
int unbin95(unsigned int input, unsigned char *output) {
int i = 0;
for (i=4; i>=0; i--) {
output[i]=nt_chars_ext95[input%95];
input/=95;
}
return 1;
}
unsigned long long int bin43(unsigned char *input) {
unsigned long long int sum = 0;
int i,l;
l = (int) strlen((char *)input);
if (l<7)
for (i=0; i<l && i<6; i++)
sum = sum*95 + (unsigned long long int)(strchr((char *)nt_chars_ext95,input[i]) - (char*)nt_chars_ext95);
else if (l==7)
for (i=0; i<7; i++)
sum = sum*62 + (unsigned long long int)(strchr((char *)nt_chars_alphanum62,input[i]) - (char*)nt_chars_alphanum62);
else if (l==8)
for (i=0; i<8; i++)
sum = sum*36 + (unsigned long long int)(strchr((char *)nt_chars_low36,input[i]) - (char*)nt_chars_low36);
sum += offset_nt[l-1];
return sum;
}
/* Find a end of chain in a table and return the corresponding
start of chain using three files: index, end and start
================================================================
*/
int binsearch(int table, char *pw, char *startpw)
{
if (!crack_type_num) { //LM CRACK
int i,l,l2;
unsigned int prefix,start,offset;
unsigned short int postfix;
unsigned short int p1[200];
int high,low;
char *p;
#ifdef WIN32
DWORD dwRead;
int* p_index = NULL;
int* p_start = NULL;
unsigned short int* p_end = NULL;
#else
int dwRead;
#endif
l2 = strlen(pw);
/*calculate prefix from first 4 bytes */
prefix=0;
l=(l2<4 ? l2 : 4);
offset=chars_size*chars_size*chars_size*chars_size;
for (i=0; i<4; i++) {
p=strchr((char *)charset,pw[i]);
if (i< l) prefix=prefix*chars_size+p-(char*)charset;
else {prefix+=offset;offset/=chars_size;}
}
//g_print("\nbinsearch: prefix %u\n",prefix);
/*calculate postfix from last 3 bytes */
postfix=0;
l=(l2>4 ? l2-4 : 0); offset=chars_size*chars_size*chars_size;
for (i=0; i<3; i++) {
p=strchr((char *)charset,pw[i+4]);
if (i< l) postfix=postfix*chars_size+p-(char*)charset;
else { postfix+=offset;offset/=chars_size; }
}
//g_print("binsearch: postfix %hu\n",postfix);
/* look-up range for this prefix in the index */
#ifndef WIN32
fseek(indexfile[table],4*prefix,SEEK_SET);
fread(&low,sizeof(low),1,indexfile[table]);
#else
if (!F_INDEX) {
SetFilePointer(indexfile[table], 4*prefix, NULL, FILE_BEGIN);
ReadFile(indexfile[table], &low, sizeof(low), &dwRead, NULL);
} else {
p_index = (int*)(indexbuff[table]+4*prefix);
low = *p_index;
}
#endif
n_fseek++;
//g_print("binsearch: low=%d\n",low);
if (low) {
#ifndef WIN32
fread(&high,sizeof(high),1,indexfile[table]);
#else
if (!F_INDEX)
ReadFile(indexfile[table], &high, sizeof(high), &dwRead, NULL);
else {
p_index++;
high = *p_index;
}
#endif
//g_print("binsearch: high=%d\n",high);
if (high) {
//g_print("binsearch: low=%d high=%d\n",low, high);
#ifndef WIN32
fseek(endfile[table],(low)*2, SEEK_SET);
fread(&p1,sizeof(unsigned short int),(high-low),endfile[table]);
#else
if (!F_END) {
SetFilePointer(endfile[table], (low)*2, NULL,FILE_BEGIN);
ReadFile(endfile[table], &p1, (high-low)*sizeof(unsigned short int), &dwRead, NULL);
} else {
//p_end = (unsigned short int*)(endbuff[table]+((low)*2));
memcpy(p1, (unsigned short int*) (endbuff[table]+((low)*2)), (high-low)*sizeof(unsigned short int));
}
#endif
n_fseek++;
i=0;
while (i<(high-low)) {
if (p1[i]==postfix)
break; /* found! */
else
i++;
}
if (i == (high-low)) return 0;
}
}
/* read start and change it to ascii: */
#ifndef WIN32
fseek(startfile[table],(low+i)*4,SEEK_SET);
fread(&start,sizeof(start),1,startfile[table]);
#else
if (!F_START) {
SetFilePointer(startfile[table], (low+i)*4, NULL, FILE_BEGIN);
ReadFile(startfile[table], &start, sizeof(start), &dwRead, NULL);
} else {
p_start = (int*)(startbuff[table]+((low+i)*4));
start = *p_start;
}
#endif
n_fseek++;
// g_print("start = %d", start);
/* Extract checkpoint from start */
checkpoint_value[0] = (start>>30) & 0x1;
checkpoint_value[1] = (start>>31) & 0x1;
start &= 0x3FFFFFFF;
startpw[6]=0;
startpw[7]=0;
for(i=5;i>=0;i--) {
startpw[i] = charset[start%36]; /* WARNING! change 36 into CHARS_SIZE */
start/=36;
}
} else { //NT CRACK
int i,l,l2;
unsigned int prefix,start;
unsigned short int postfix;
unsigned short int p1[200];
unsigned long long int pw_bin;
int high,low;
char *p;
#ifdef WIN32
DWORD dwRead;
int* p_index = NULL;
int* p_start = NULL;
unsigned short int* p_end = NULL;
#else
int dwRead;
#endif
pw_bin = bin43((unsigned char *)pw);
prefix = (unsigned int) (pw_bin >>18 & 0x00000000FFFFFFFF);
postfix = (unsigned short int) (pw_bin & 0x000000000000FFFF);
/* look-up range for this prefix in the index */
#ifndef WIN32
fseek(indexfile[table],4*prefix,SEEK_SET);
fread(&low,sizeof(low),1,indexfile[table]);
#else
if (!F_INDEX) {
SetFilePointer(indexfile[table], 4*prefix, NULL, FILE_BEGIN);
ReadFile(indexfile[table], &low, sizeof(low), &dwRead, NULL);
} else {
p_index = (int*)(indexbuff[table]+4*prefix);
low = *p_index;
}
#endif
n_fseek++;
//g_print("binsearch: low=%d\n",low);
if (low) {
#ifndef WIN32
fread(&high,sizeof(high),1,indexfile[table]);
#else
if (!F_INDEX)
ReadFile(indexfile[table], &high, sizeof(high), &dwRead, NULL);
else {
p_index++;
high = *p_index;
}
#endif
//g_print("binsearch: high=%d\n",high);
if (high) {
//g_print("binsearch: low=%d high=%d\n",low, high);
#ifndef WIN32
fseek(endfile[table],(low)*2, SEEK_SET);
fread(&p1,sizeof(unsigned short int),(high-low),endfile[table]);
#else
if (!F_END) {
SetFilePointer(endfile[table], (low)*2, NULL,FILE_BEGIN);
ReadFile(endfile[table], &p1, (high-low)*sizeof(unsigned short int), &dwRead, NULL);
} else {
//p_end = (unsigned short int*)(endbuff[table]+((low)*2));
memcpy(p1, (unsigned short int*) (endbuff[table]+((low)*2)), (high-low)*sizeof(unsigned short int));
}
#endif
n_fseek++;
i=0;
while (i<(high-low)) {
if (p1[i]==postfix)
break; /* found! */
else
i++;
}
if (i == (high-low)) return 0;
}
}
/* read start and change it to ascii: */
#ifndef WIN32
fseek(startfile[table],(low+i)*4,SEEK_SET);
fread(&start,sizeof(start),1,startfile[table]);
#else
if (!F_START) {
SetFilePointer(startfile[table], (low+i)*4, NULL, FILE_BEGIN);
ReadFile(startfile[table], &start, sizeof(start), &dwRead, NULL);
} else {
p_start = (int*)(startbuff[table]+((low+i)*4));
start = *p_start;
}
#endif
n_fseek++;
// g_print("start = %d", start);
startpw[5]=0;
startpw[6]=0;
startpw[7]=0;
unbin95(start, (unsigned char *)startpw);
}
return 1;
}
/* Find the password corresponing to HASH in a given table, at a given
column and starting with a given reduction function
=================================================== */
int find(unsigned char *hash, char *found, int col, int table)
{
if (!crack_type_num) { // LM CRACK
unsigned char h[8];
static char pw[8], start[8];
static int i,l;
int checkpoint_found[2]={0};
//g_print("\nfind: col=%d table=%d\n",col,table);
set_redux(col, table);
/* advance to end of chain */
/* we can save this work if we are in parallel mode, above ident_redux and
* not in the first table and doing the tree-table optimization... */
if (table==first_table || col < ident_col) {
make_redux(hash,(unsigned char *)pw);
//g_print("find: %d,%s ",n_redux,pw);
for (l=1; l<cols-col; l++) {
make_hash((unsigned char *)pw,h);
next_redux();
make_redux(h,(unsigned char *)pw);
//g_print("%d,%s ",n_redux,pw);
if ((chkpt1 != -1) && (chkpt2 !=-1)) {
if ((col+l+1) == chkpt1)
checkpoint_found[0] = pw[0] & 0x1;
if ((col+l+1) == chkpt2)
checkpoint_found[1] = pw[0] & 0x1;
}
}
n_hashredux+=l;
//g_print("%-7.7s\n",pw);
//g_print("find: n_hashredux=%d l=%d\n",n_hashredux,l);
}
while (gtk_events_pending ())
gtk_main_iteration ();
/* look up the end in the table and get the start */
if (binsearch(table,pw,start)) {
n_match++;
if ((chkpt1 != -1) && (chkpt2 !=-1)) {
if (!((checkpoint_value[0] == checkpoint_found[0])
&& (checkpoint_value[1] == checkpoint_found[1]))) {
n_cp_false++;
return 0;
}
}
set_redux(0, table);
/* advance to the colunm that we are exploring */
for (i=l; i<=cols-1; i++) {
make_hash((unsigned char *)start,h);
make_redux(h,(unsigned char *)start);
next_redux();
n_hashredux++;
}
make_hash((unsigned char *)start,h);
/* check if we get the same hash: */
if (!memcmp(&h,hash,sizeof(h))) {
strncpy(found,start,8);
//g_print("find: found in table %d\n",table);
return 1;
}
else {
/* false alarm! */
n_false++;
n_false_redux += cols-l;
}
}
} else { //NT CRACK
unsigned char h[16];
static char pw[16], start[16];
static int i,l;
set_redux(col, table);
/* advance to end of chain */
if (table==first_table || col < ident_col) {
make_redux(hash,(unsigned char *)pw);
//g_print("find: %d,%s ",n_redux,pw);
for (l=1; l<cols-col; l++) {
make_nthash(pw,(char *)h);
next_redux();
make_redux(h,(unsigned char *)pw);
//g_print("%d,%s ",n_redux,pw);
}
n_hashredux+=l;
//g_print("%-7.7s\n",pw);
//g_print("find: n_hashredux=%d l=%d\n",n_hashredux,l);
}
while (gtk_events_pending ())
gtk_main_iteration ();
/* look up the end in the table and get the start */
if (binsearch(table,pw,start)) {
n_match++;
set_redux(0, table);
/* advance to the colunm that we are exploring */
for (i=l; i<=cols-1; i++) {
make_nthash(start,(char *)h);
make_redux(h,(unsigned char *)start);
next_redux();
n_hashredux++;
}
make_nthash(start,(char *)h);
/* check if we get the same hash: */
if (!memcmp(&h,hash,sizeof(h))) {
strncpy(found,start,16);
//g_print("find: found in table %d\n",table);
return 1;
}
else {
/* false alarm! */
n_false++;
n_false_redux += cols-l;
}
}
}
return 0;
}
/* Read two halfs of LMHash and possibly NTHash and info from string */
int get_hashes(unsigned char lmhash_1[], unsigned char lmhash_2[],
char nthash[], unsigned char *info, int *userid,
char *password1, char *password2, char *password,
int *done1, int *done2, char *h)
{
/* following formats are supported:
lmhash
lmhash:nthash
username:userid:lmhash:nthash:passwd1:passwd2:passwd (like pwdump2)
*/
unsigned int i,k,l;
char *p[8] = {0};
unsigned char *tmp;
l=0;
p[l]=strsep(&h,":");
while (l<8){
l++;
if (!(p[l]=strsep(&h,":")) ) break;
}
if (l==7) {
if (strcmp(p[0],"")) strncpy((char *)info,p[0],64);
if (strcmp(p[1],"")) *userid = atoi(p[1]);
if (!strcmp(p[2],"NO PASSWORD*********************")) {
memcpy(lmhash_1, empty_hash, 8);
memcpy(lmhash_2, empty_hash, 8);
}
else
for (i=0; i<8; i++) {
if (sscanf(p[2]+2*i,"%2x",&k) !=1 )
return 0;
lmhash_1[i]=(unsigned char)k;
if (sscanf(p[2]+2*i+16,"%2x",&k) !=1 )
return 0;
lmhash_2[i]=(unsigned char)k;
}
if (strcmp(p[3],"")){
if (!strcmp(p[3],"NO PASSWORD*********************"))
memcpy(nthash, empty_nt_hash, 16);
else
for (i=0;i<16;i++)
if (sscanf(p[3]+2*i,"%2hhx",(unsigned char *)&nthash[i])!=1)
return 0;
} else
nthash[0]=0;
/* thanks to BaLP */
if (strcmp(p[4],"")) {
strncpy(password1, p[4], strlen(p[4]));
for (tmp = (unsigned char *)password1; (*tmp = (*tmp == 193U ? ':' : *tmp)); ++tmp);
*done1=1;
}
if (strcmp(p[5], "")) {
strncpy(password2, p[5], strlen(p[5]));
for (tmp = (unsigned char *)password2; (*tmp = (*tmp == 193U ? ':' : *tmp)); ++tmp);
*done2=1;
}
strncpy(password, p[6], strlen(p[6]));
for (tmp = (unsigned char *)password; (*tmp = (*tmp == 193U ? ':' : *tmp)); ++tmp);
} else {
if (!strcmp(p[0],"NO PASSWORD*********************")) {
memcpy(lmhash_1, empty_hash, 8);
memcpy(lmhash_2, empty_hash, 8);
}
else
for (i=0; i<8; i++) {
if (sscanf(p[0]+2*i,"%2x",&k) !=1 )
return 0;
lmhash_1[i]=(unsigned char)k;
if (sscanf(p[0]+2*i+16,"%2x",&k) !=1 )
return 0;
lmhash_2[i]=(unsigned char)k;
}
if (l>1) {
if (strcmp(p[1],"")){
if (!strcmp(p[1],"NO PASSWORD*********************"))
memcpy(nthash, empty_nt_hash, 16);
else
for (i=0;i<16;i++)
if (sscanf(p[1]+2*i,"%2hhx",(unsigned char *)&nthash[i])!=1)
return 0;
}
}
}
return 1;
}
int read_line(char *line) {
if (get_hashes(lm_hash1[hashes],lm_hash2[hashes],
(char *)nt_hash[hashes],(unsigned char *)info[hashes], &userid[hashes],
password1[hashes], password2[hashes],
password[hashes],&done1[hashes], &done2[hashes],line)) {
hashes++;
return 1;
} else {
return 0;
}
}
int remove_line(int hash) {
int diff;
diff=hashes-hash;
if (diff>0) {
memmove(lm_hash1[hash], lm_hash1[hash+1], diff*sizeof(lm_hash1[hash]));
memmove(lm_hash2[hash], lm_hash2[hash+1], diff*sizeof(lm_hash2[hash]));
memmove(nt_hash[hash], nt_hash[hash+1], diff*sizeof(nt_hash[hash]));
memmove(info[hash], info[hash+1], diff*sizeof(info[hash]));
memmove(&userid[hash], &userid[hash+1], diff*sizeof(&userid[hash]));
memmove(password1[hash], password1[hash+1], diff*sizeof(password1[hash]));
memmove(password2[hash], password2[hash+1], diff*sizeof(password2[hash]));
memmove(password[hash], password[hash+1], diff*sizeof(password[hash]));
memmove(&done1[hash], &done1[hash+1], diff*sizeof(&done1[hash]));
memmove(&done2[hash], &done2[hash+1], diff*sizeof(&done2[hash]));
}
hashes--;
}
int resolve_nt_hash(char p1[], char p2[], char h[], char pw[])
{
unsigned int i;
unsigned int k=0,l;
unsigned char md4[17],*p;
bzero(pw,15);
strcpy(pw,p1);
strcpy(&pw[7],p2);
md4[16]=0;
for (i=0; i<16384; i++) {
l = k ^ i ^ (i>>1);
k = i ^ (i>>1);
p = (unsigned char *)pw; while ((l=l>>1)) p++;
*p=(*p>91?toupper(*p):tolower(*p));
make_nthash(pw,(char *)md4);
if (!memcmp(md4,h,16)) {
return 1;
}
}
return 0;
}
/* Display password and progress indication */
void display(int h, int k)
{
int i;
if (h==-1)
printf("%-32s : %-14s\n","username or lmhash","password");
if (h>= 0) {
if (info[h][0])
printf("%-32s : ",info[h]);
else {
for (i=0; i<8; i++) printf("%02hhx",lm_hash1[h][i]);
for (i=0; i<8; i++) printf("%02hhx",lm_hash2[h][i]);
printf(" : ");
}
if (resolve_nt_hash(password1[h],password2[h], (char *)nt_hash[h],password[h]) )
printf("%-14s \n",password[h]);
else
printf("%-7s%-7s \n",password1[h],password2[h]);
}
if (!quiet) {
#ifndef WIN32
laps_time = times(&n_times);
#else /* WIN32 */
laps_time = clock();
#endif /* WIN32 */
printf("[tables:%d-%d,%2d%% passwords:%d/%d seconds/pw:%.2f]\r",
first_table,
last_table,
100-(100*k)/cols,
n_found, hashes,
(n_found?(float)(laps_time - n_start_time)/ticks/n_found:0));
}
}
int read_file(char* filename) {
char c;
char *line;
int size = 199;
FILE *hash_file;
clear_passwd_arrays();
hashes = 0;
n_found = 0;
/* get hash from command line or from file: */
if (!(hash_file=fopen(filename,"r"))) {
//g_print("%s is neither a valid hash or a filename\n\n\n",filename);
return 0;
}
line = malloc(size+1);
/* Get hashes from file into table */
fgets(line, 199, hash_file);
if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = 0; //remove newline
while (!feof(hash_file) && (hashes <MAX_HASH)) {
if (get_hashes(lm_hash1[hashes],lm_hash2[hashes],
(char *)nt_hash[hashes],(unsigned char *)info[hashes], &userid[hashes],
password1[hashes], password2[hashes],
password[hashes],&done1[hashes], &done2[hashes],line))
//printf("invalid hash found in hash file: %s\n",line);
//else
hashes++;
fgets(line, 199, hash_file);
if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = 0;
}
if (hashes == MAX_HASH)
show_error_max_hash();
fclose(hash_file);
return hashes;
}
void clear_passwd_arrays(void) {
int i;
for (i=0; i<hashes; i++) {
bzero(info[i], sizeof(info[i]));
bzero(lm_hash1[i], sizeof(lm_hash1[i]));
bzero(lm_hash2[i], sizeof(lm_hash2[i]));
bzero(nt_hash[i], sizeof(nt_hash[i]));
userid[i]=0;
bzero(password1[i], sizeof(password1[i]));
bzero(password2[i], sizeof(password2[i]));
bzero(password[i], sizeof(password[i]));
done1[i]=0;
done2[i]=0;
}
}
int auto_detect_tables(char *directory) {
unsigned char filename[256];
unsigned char configfilename[256];
FILE *file;
unsigned int buff;
char *parameter;
FILE *configfile;
char *line = (char *)malloc(100*sizeof(char));
/* test if we know the tables */
sprintf((char *)filename,"%s/table0.bin",directory);
if (file=fopen((char *)filename, "r")) {
fread(&buff, sizeof(int), 1, file);
switch(buff) {
case 0x3cc21790 : table_type = 0; cols=10000; batch_tables=1;
last_table=3; offset=10000; break;
case 0x0fa2031c : table_type = 1; cols=5000; offset = 10000;
batch_tables = 1; last_table = 3; break;
case 0x0e3402df :
case 0xc7ed7df5 :
sprintf((char *)configfilename,"%s/tables.cfg",directory);
if (!(configfile=fopen((char *)configfilename,"r"))) {
return 0;
}
else {
while( fgets(line, 99, configfile) != NULL ) {
parameter = (char *)strsep(&line,"=");
if (!strcmp(parameter, "table_type"))
table_type = atoi(line);
if (!strcmp(parameter, "cols"))
cols = atoi(line);
if (!strcmp(parameter, "offset"))
offset = atoi(line);
if (!strcmp(parameter, "chkpt1"))
chkpt1 = atoi(line);
if (!strcmp(parameter, "chkpt2"))
chkpt2 = atoi(line);
if (!strcmp(parameter, "crack_type"))
strncpy(crack_type, line, 2);
}
}
break;
default: fclose(file); return 0; break;
}
fclose(file);
return 1;
} else return 0;
}
int find_tables() {
#ifdef WIN32
strcpy(directory, "5000");
#else
snprintf(directory, 127, "%s/5000", TDIR);
#endif
if (access(directory, F_OK) == 0) {
auto_detect_tables(directory);
}
else {
#ifdef WIN32
strcpy(directory, "10000");
#else
snprintf(directory, 127, "%s/10000", TDIR);
#endif
if (access(directory, F_OK) == 0) {
auto_detect_tables(directory);
}
}
n_found = 0;
if (!offset) offset=cols;
}
#ifndef WIN32
int clean_ram(unsigned long int size) {
/* clean page cache (very dirty...) */
unsigned long int i;
char *ptr;
show_clean_window();
ptr = (char*)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
if (ptr!= MAP_FAILED) {
for (i=0; i<size; ++i) {
*(ptr + i) = 1;
}
munmap(ptr, size);
}
hide_readahead_window();
return 0;
}
#endif
int evaluate_ram() {
#ifdef WIN32
MEMORYSTATUS stat;
DWORD filesize[3];
#else
struct stat buf;
//struct sysinfo info;
size_t filesize[3];
int fd;
#endif
#ifdef HAVE_SYS_SYSINFO_H
struct sysinfo info;
#elif defined(HAVE_SYS_SYSCTL_H)
int mib[2] = {CTL_HW, HW_PHYSMEM}, mem;
size_t len;
#endif
long int totalram,freeram;
/* calculate table size*/
#ifndef WIN32
fd = fileno(indexfile[first_table]);
fstat(fd, &buf);
filesize[0] = (size_t)buf.st_size;
fd = fileno(endfile[first_table]);
fstat(fd, &buf);
filesize[1] = (size_t)buf.st_size +filesize[0];
fd = fileno(startfile[first_table]);
fstat(fd, &buf);
filesize[2] = (size_t)buf.st_size +filesize[1];
#else
filesize[0] = GetFileSize(indexfile[first_table], NULL);
filesize[1] = GetFileSize(endfile[first_table], NULL) + filesize[0];
filesize[2] = GetFileSize(startfile[first_table], NULL) +filesize[1];
#endif
batch_tables=1;
size_to_clean = (unsigned long int) filesize[2];
/* retrieve system info */
#if HAVE_SYS_SYSINFO_H
sysinfo(&info);
totalram = (long int)info.totalram - RAM_FOR_SYSTEM*1024*1024;
freeram = (long int)info.freeram;
#elif HAVE_SYS_SYSCTL_H
len = sizeof(mem);
if (sysctl(mib, 2, &mem, &len, NULL, 0) == 0) {
totalram = mem - RAM_FOR_SYSTEM*1024*1024;
} else {
perror("sysctl");
exit(-1);
}
mib[1] = HW_USERMEM;
len = sizeof(mem);
if (sysctl(mib, 2, &mem, &len, NULL, 0) == 0) {
freeram = mem;
} else {
perror("sysctl");
exit(-1);
}
#elif defined(WIN32)
GlobalMemoryStatus (&stat);
totalram = 0;
freeram = (long int)stat.dwAvailPhys;
#else
#error do not know how to get RAM information
#endif
#ifndef WIN32
//g_print("%d%d%d %d %u %d %d\n", F_INDEX, F_END, F_START, batch_tables, batch_tables*filesize[2], freeram, totalram);
if (totalram < freeram) totalram=freeram;
if (size_to_clean > totalram)
size_to_clean = totalram;
while ((size_to_clean*batch_tables) < totalram) {
batch_tables++;
}
if (batch_tables >1) batch_tables--;
if (batch_tables > last_table +1)
batch_tables = last_table+1;
size_to_clean *= batch_tables;
//g_print("%d%d%d %d %u %d %d\n", F_INDEX, F_END, F_START, batch_tables, batch_tables*filesize[2], freeram, totalram);
/* clean ram */
clean_ram(size_to_clean);
/* reevaluate available ram */
#if HAVE_SYS_SYSINFO_H
sysinfo(&info);
freeram = (long int)info.freeram;
#elif HAVE_SYS_SYSCTL_H
mib[0] = CTL_HW;
mib[1] = HW_USERMEM;
len = sizeof(mem);
if (sysctl(mib, 2, &mem, &len, NULL, 0) == 0) {
freeram = mem;
} else {
perror("sysctl");
exit(-1);
}
#else
#error do not know how to get RAM information
#endif
#endif
#if HAVE_READAHEAD
if (freeram < size_to_clean) {
if (filesize[0]>freeram) {
F_INDEX=1; F_END = 0; F_START = 0; batch_tables = 1;
}
else if (filesize[1]>freeram) {
F_INDEX=1; F_END = 1; F_START = 0; batch_tables = 1;
}
else {
F_INDEX=1; F_END = 1; F_START = 1; batch_tables = 1;
}
} else {
F_INDEX=1; F_END = 1; F_START = 1; batch_tables = 1;
size_to_clean = (long int)filesize[2];
while ((size_to_clean*batch_tables) < freeram) {
batch_tables++;
}
if (batch_tables >1) batch_tables--;
}
//g_print("%d%d%d %d %u %d %d\n", F_INDEX, F_END, F_START, batch_tables, batch_tables*filesize[2], freeram, totalram);
#else /* no READAHEAD*/
if (freeram < size_to_clean) {
if (filesize[0]>freeram) {
F_INDEX=0; F_END = 0; F_START = 0; batch_tables = 1;
}
else if (filesize[1]>freeram) {
F_INDEX=1; F_END = 0; F_START = 0; batch_tables = 1;
}
else {
F_INDEX=1; F_END = 1; F_START = 0; batch_tables = 1;
}
} else {
F_INDEX=1; F_END = 1; F_START = 1; batch_tables = 1;
size_to_clean = (long int)filesize[2];
while ((size_to_clean*batch_tables) < freeram) {
batch_tables++;
}
if (batch_tables >1) batch_tables--;
}
// if ((batch_tables ==1) && (2*size_to_clean < totalram)) batch_tables++;
#endif
}
#ifdef LIVECD
int init_livecd(char *dir) {
bzero(directory, strlen(directory));
strncpy(directory, dir, strlen(dir));
cols = 10000;
offset = 10000;
first_table=0;
last_table=3;
batch_tables = 4;
table_type = 0;
activate_launch_toggle();
}
#endif
/* MAIN
==== */
int main_cmd()
{
extern int optind;
extern char *optarg;
int h, i, k, t, table, f_t, l_t;
int display_step;
/* disabled for GUI
while ((c=getopt(argc, argv, "qn:d:vt:o:si:f:l:"))>0) {
switch ((char)c) {
case 'd': strcpy(directory, optarg); break;
case 't': cols = atoi(optarg); break;
case 'o': offset = atoi(optarg); break;
case 'i': ident_col = atoi(optarg); break;
case 'v': verbose=1;break;
case 's': stats = 1; init_stats(); break;
case 'f': first_table = atoi(optarg); break;
case 'l': last_table = atoi(optarg); break;
case 'n': batch_tables = atoi(optarg); break;
case 'q': quiet = 1; break;
case '?': usage(argv[0]);break;
}
}
*/
n_found=0;
init_redux(offset,ident_col);
/* find out how many ticks we have per second */
#ifndef WIN32
ticks = sysconf(_SC_CLK_TCK);
#else /* WIN32 */
ticks = CLOCKS_PER_SEC;
#endif /* WIN32 */
/* open all table files */
if (!open_tables)
if (!open_files(directory)) return -2;
//read_file - GUI
to_go = 3*hashes;
if (!strcmp(crack_type, "LM"))
crack_type_num=0;
else
crack_type_num=1;
/* Eliminate empty ones: */
for (i=0; i<hashes; i++) {
if (!memcmp(lm_hash1[i],empty_hash,
sizeof(lm_hash1[i]))) {
strcpy(password1[i],"/EMPTY/");
done1[i]=1;
}
if (!memcmp(lm_hash2[i],empty_hash,
sizeof(lm_hash2[i]))) {
done2[i]=1;
}
if (!memcmp(nt_hash[i], empty_nt_hash, sizeof(nt_hash[i])) || !strncmp((char *)nt_hash[i], "", 2)) {
strcpy(password[i],"/EMPTY/");
done_nt[i]=1;
}
if (done1[i])
to_go--;
if (done2[i])
to_go--;
if (done_nt[i])
to_go--;
if (done1[i] && done2[i] && done_nt[i])
n_found++;
if (!done1[i]) bzero(password1[i], sizeof(password1[i]));
if (!done2[i]) bzero(password2[i], sizeof(password2[i]));
if (!done_nt[i]) bzero(password[i], sizeof(password[i]));
}
fill_tree();
if (!to_go)
return(1);
//g_print("togo: %d\n", to_go);
/* search all passwords in all tables: */
/* ================================== */
display_step = cols/100;
/* for each batch: */
f_t = first_table; l_t= last_table;
evaluate_ram();
init_stats();
/* g_print("cols %d, offset %d, f_t %d, l_t %d, chkpt1 %d, chkpt2 %d, batch %d, chars_size %d\n", cols, offset, f_t, l_t, chkpt1, chkpt2, batch_tables, chars_size);
for (i=0; i<chars_size; i++)
g_print("%c", charset[i]);
g_print("\n");
*/
for (t=f_t; t<= l_t; t+=batch_tables) {
first_table = t;
last_table = t+batch_tables-1>l_t? l_t : t+batch_tables-1;
#if HAVE_READAHEAD
if (t>f_t)
clean_ram(size_to_clean);
#elif defined(WIN32)
for (i=first_table-batch_tables; i<first_table && (i>-1); i++) {
if (F_START && startbuff[i]) {
free(startbuff[i]);
startbuff[i] = 0;
}
if (F_END && endbuff[i]){
free(endbuff[i]);
endbuff[i] = 0;
}
if (F_INDEX && indexbuff[i]){
free(indexbuff[i]);
indexbuff[i] = 0;
}
}
#endif
for (table=first_table; table<= last_table; table++)
#if HAVE_READAHEAD
/* readahead, preload the table in file cache
* ED 28.8.2005 */
{
int readahead_result,fd;
struct stat buf;
size_t filesize;
show_readahead_window(table);
while (gtk_events_pending())
gtk_main_iteration();
if (F_START) {
fd = fileno(startfile[table]);
fstat(fd, &buf);
filesize = (size_t)buf.st_size;
readahead_result = readahead(fd,(loff_t)0,filesize);
if(readahead_result == -1) perror("readahead");
}
if (F_END) {
fd = fileno(endfile[table]);
fstat(fd, &buf);
filesize = (size_t)buf.st_size;
readahead_result = readahead(fd,(loff_t)0,filesize);
if(readahead_result == -1) perror("readahead");
}
if (F_INDEX) {
fd = fileno(indexfile[table]);
fstat(fd, &buf);
filesize = (size_t)buf.st_size;
readahead_result = readahead(fd,(loff_t)0,filesize);
if(readahead_result == -1) perror("readahead");
}
hide_readahead_window();
}
/* end readahead */
#elif defined(WIN32)
{
long size;
DWORD dwRead;
show_readahead_window(table);
while (gtk_events_pending())
gtk_main_iteration();
if (F_START) {
size = GetFileSize(startfile[table], NULL);
if (startbuff[table] = (unsigned char*) malloc (size))
ReadFile(startfile[table], startbuff[table], size, &dwRead, NULL);
else
F_START = 0;
}
if (F_END) {
size = GetFileSize(endfile[table], NULL);
if (endbuff[table] = (unsigned char*) malloc (size))
ReadFile(endfile[table], endbuff[table], size, &dwRead, NULL);
else
F_END = 0;
}
if (F_INDEX) {
size = GetFileSize(indexfile[table], NULL);
if (indexbuff[table] = (unsigned char*) malloc (size))
ReadFile(indexfile[table], indexbuff[table], size, &dwRead, NULL);
else
F_INDEX = 0;
}
hide_readahead_window();
}
#endif
/* for each column of the tables */
for (k=cols-1; k>=0; k--) {
/* if (!quiet)
if (!(k%display_step))
display (-2,k);
*/
update_statusbar(k);
/* for each file containing a table: */
for (table=first_table; table<=last_table; table++) {
while (gtk_events_pending ()) {
if (STOP) {
close_files();
return (0);
}
gtk_main_iteration ();
}
/* for each password: */
for (h=0; h<hashes || !to_go; h++) {
if (!crack_type_num) { //LM CRACK
if (!done1[h]) {
n_search++;
if (find(lm_hash1[h], password1[h], k, table)) {
change_tree(h);
to_go--;
done1[h]=1;
if (done2[h]) {
if (done_nt[h] || resolve_nt_hash(password1[h],password2[h],(char *)nt_hash[h],password[h]))
{n_found++; to_go--; done_nt[h]=1;}
change_tree(h);
//display(h,k);
update_statusbar(k);
}
if (!to_go) break;
}
}
if (!done2[h]) {
n_search++;
if (find(lm_hash2[h], password2[h], k, table)) {
change_tree(h);
done2[h]=1;
to_go--;
if (done1[h]) {
if (done_nt[h] || resolve_nt_hash(password1[h],password2[h],(char *)nt_hash[h],password[h]))
{n_found++; to_go--; done_nt[h]=1;}
change_tree(h);
//display(h,k);
update_statusbar(k);}
if (!to_go) break;
}
}
} else { //NT CRACK
if (!done_nt[h]) {
n_search++;
if (find(nt_hash[h], password[h], k, table)) {
change_tree(h);
done_nt[h]=1;
n_found++;
to_go--;
update_statusbar(k);
if (!to_go) break;
}
}
}
}
if (!to_go) break;
}
if (!to_go) break;
}
if (!to_go) break;
}
/* display hashes that have not been fully cracked: */
for (h=0; h<hashes;h++)
if (!done1[h] || !done2[h] || !done_nt[h]){
if (!done1[h]) strcpy(password1[h],".......");
if (!done2[h]) strcpy(password2[h],".......");
if (!done_nt[h]) strcpy(password[h], "Not found");
fill_tree();
}
print_stats();
close_files();
return (1);
}